#ifndef ADHOCVISITOR_H
#define ADHOCVISITOR_H
#include <loki/typelist.h>
template <class tlist> class AdHocVisitor;
//
//class Effector
//{
//    void Visit(Horse*);
//    void Visit(Dog*);
//};
//
template <class H, class T>
class AdHocVisitor< typeList<H, T> >: public AdHocVisitor<T>
{
public:
    using AdHocVisitor<T>::Visit;
    virtual void Visit(H*) = 0;
    template <class SomeClass>
    void StartVisit(SomeClass* p)
    {
        if (H* pFound = dynamic_cast<H*>(p))
        {
            Visit(pFound);
        }
        else
        {
            AdHocVisitor<T>::StartVisit(p);
        }
    }
};

template <class H>
class AdHocVisitor<typelist<H, null_typelist> >
{
public:
    virtual void Visit(H*) = 0;
    template <class SomeClass>
    void StartVisit (SomeClass* p)
    {
        if (H* pFound = dynamic_cast<H*>(p))
        {
            Visit(pFound);
        }
        else
        {
            throw "Unknown type passed";
        }
    }
};

template <class tlist, class Effecter> class FlexAdHocVistor;
template <class H, class T, class Effecter>
class FlexAdHocVistor< typeList<H, T> ,Effecter>: public FlexAdHocVistor<T, Effecter >, virtual public Effecter
{
public:
    template <class SomeClass>
    void StartVisit(SomeClass* p)
    {
        if (H* pFound = dynamic_cast<H*>(p))
        {
            typedef void (Effecter::*PVistor)(H*);
            PVisitor pvistor = Effecter::Visit;//check
            Effecter::Visit(pFound);
        }
        else
        {
            FlexAdHocVistor<T>::StartVisit(p);
        }
    }
};

template <class H,class Effecter>
class FlexAdHocVistor<typelist<H, null_typelist>,  Effecter >:virtual public Effecter
{
public:
    template <class SomeClass>
    void StartVisit (SomeClass* p)
    {
        if (H* pFound = dynamic_cast<H*>(p))
        {
            typedef void (Effecter::*PVistor)(H*);
            PVisitor pvistor = Effecter::Visit;//check
            Effecter::Visit(pFound);
        }
        else
        {
            throw "Unknown type passed";
        }
    }
};

template <class tlist, template <class T> Effecter> class FlexAdHocVistor;
template <class H, class T,template <class T> Effecter>
class FlexAdHocVistor< typeList<H, T> ,Effecter>: public FlexAdHocVistor<T >, public Effecter<H>
{
public:
    template <class SomeClass>
    void StartVisit(SomeClass* p)
    {
        if (H* pFound = dynamic_cast<H*>(p))
        {
            Effecter<H>::Visit(pFound);
        }
        else
        {
            FlexAdHocVistor<T>::StartVisit(p);
        }
    }
};

template <class H, template <class T> Effecter>
class FlexAdHocVistor<typelist<H, null_typelist>,  Effecter >: public Effecter<H>
{
public:
    template <class SomeClass>
    void StartVisit (SomeClass* p)
    {
        if (H* pFound = dynamic_cast<H*>(p))
        {
            Effecter<H>::Visit(pFound);
        }
        else
        {
            throw "Unknown type passed";
        }
    }
};

#endif
